﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SharpPcap;
using SharpPcap.Packets;

namespace PacketHandler
{
    public static class DotaPacketHandler
    {
        public delegate void DotaChatEventHandler(String message);
        public static event DotaChatEventHandler ChatMessageReceived;
        public static event DotaChatEventHandler MotDMessageReceived;

        static List<Action> gameActions = new List<Action>();

        public static List<Action> GameActions
        {
            get { return DotaPacketHandler.gameActions; }
        }


        enum RealmPacketIDConstants : byte
        {

            // Realm Messages Constants
            // -------------------

            MCP_STARTUP = 0x01,
            MCP_CHARCREATE = 0x02,
            MCP_CREATEGAME = 0x03,
            MCP_JOINGAME = 0x04,
            MCP_GAMELIST = 0x05,
            MCP_GAMEINFO = 0x06,
            MCP_CHARLOGON = 0x07,
            MCP_CHARDELETE = 0x0A,
            MCP_REQUESTLADDERDATA = 0x11,
            MCP_MOTD = 0x12,
            MCP_CANCELGAMECREATE = 0x13,
            MCP_CREATEQUEUE = 0x14,
            MCP_CHARLIST = 0x17,
            MCP_CHARUPGRADE = 0x18,
            MCP_CHARLIST2 = 0x19
        };

        enum BotNetPacketIDConstants : byte
        {

            // BotNet Messages Constants
            // -------------------

            PACKET_IDLE = 0x00,
            PACKET_LOGON = 0x01,
            PACKET_STATSUPDATE = 0x02,
            PACKET_DATABASE = 0x03,
            PACKET_MESSAGE = 0x04,
            PACKET_CYCLE = 0x05,
            PACKET_USERINFO = 0x06,
            PACKET_USERLOGGINGOFF = 0x07,
            PACKET_BROADCASTMESSAGE = 0x07,
            PACKET_COMMAND = 0x08,
            PACKET_CHANGEDBPASSWORD = 0x09,
            PACKET_BOTNETVERSION = 0x0A,
            PACKET_BOTNETCHAT = 0x0B,
            PACKET_ACCOUNT = 0x0D,
            PACKET_CHATDROPOPTIONS = 0x10
        };


        enum BNLSPacketIDConstants : byte
        {

            // BNLS Messages Constants
            // -------------------

            BNLS_NULL = 0x00,
            BNLS_CDKEY = 0x01,
            BNLS_LOGONCHALLENGE = 0x02,
            BNLS_LOGONPROOF = 0x03,
            BNLS_CREATEACCOUNT = 0x04,
            BNLS_CHANGECHALLENGE = 0x05,
            BNLS_CHANGEPROOF = 0x06,
            BNLS_UPGRADECHALLENGE = 0x07,
            BNLS_UPGRADEPROOF = 0x08,
            BNLS_VERSIONCHECK = 0x09,
            BNLS_CONFIRMLOGON = 0x0A,
            BNLS_HASHDATA = 0x0B,
            BNLS_CDKEY_EX = 0x0C,
            BNLS_CHOOSENLSREVISION = 0x0D,
            BNLS_AUTHORIZE = 0x0E,
            BNLS_AUTHORIZEPROOF = 0x0F,
            BNLS_REQUESTVERSIONBYTE = 0x10,
            BNLS_VERIFYSERVER = 0x11,
            BNLS_RESERVESERVERSLOTS = 0x12,
            BNLS_SERVERLOGONCHALLENGE = 0x13,
            BNLS_SERVERLOGONPROOF = 0x14,
            BNLS_VERSIONCHECKEX = 0x18,
            BNLS_VERSIONCHECKEX2 = 0x1A,
        };



        public static bool ProcessBattleNetPacket(Packet GamePacket)
        {
            BattleNetPacket b = new BattleNetPacket(GamePacket);

#if DEBUG
            String packetString = ASCIIEncoding.ASCII.GetString(GamePacket.Data);
            //Console.WriteLine("Packet Type: {0}", b.PacketType);
#endif

            if (GamePacket is TCPPacket)
            {
                switch (b.PacketType)
                {
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_NULL:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_STOPADV:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_SERVERLIST:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_CLIENTID:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_STARTVERSIONING:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_REPORTVERSION:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_STARTADVEX:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_GETADVLISTEX:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_ENTERCHAT:
                        BattleNetEnterChatPacket chatPacket = new BattleNetEnterChatPacket(GamePacket);
                        Console.WriteLine("{0}", chatPacket.GetName());
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_GETCHANNELLIST:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_JOINCHANNEL:
                        BattleNetJoinChannelPacket joinChannelPacket = new BattleNetJoinChannelPacket(GamePacket);
                        String channel = joinChannelPacket.Channel;
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_CHATCOMMAND:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_CHATEVENT:
                        BattleNetChatEventPacket chatEventPacket = new BattleNetChatEventPacket(GamePacket);
                        Console.WriteLine("{0}: {1}", chatEventPacket.GetName(), chatEventPacket.GetMessage());
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_LEAVECHAT:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_LOCALEINFO:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_FLOODDETECTED:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_UDPPINGRESPONSE:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_CHECKAD:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_CLICKAD:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_REGISTRY:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_MESSAGEBOX:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_STARTADVEX2:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_GAMEDATAADDRESS:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_STARTADVEX3:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_LOGONCHALLENGEEX:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_CLIENTID2:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_LEAVEGAME:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_DISPLAYAD:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_NOTIFYJOIN:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_PING:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_READUSERDATA:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_WRITEUSERDATA:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_LOGONCHALLENGE:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_LOGONRESPONSE:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_CREATEACCOUNT:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_SYSTEMINFO:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_GAMERESULT:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_GETICONDATA:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_GETLADDERDATA:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_FINDLADDERUSER:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_CDKEY:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_CHANGEPASSWORD:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_CHECKDATAFILE:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_GETFILETIME:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_QUERYREALMS:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_PROFILE:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_CDKEY2:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_LOGONRESPONSE2:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_CHECKDATAFILE2:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_CREATEACCOUNT2:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_LOGONREALMEX:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_STARTVERSIONING2:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_QUERYREALMS2:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_QUERYADURL:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_WARCRAFTGENERAL:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_NETGAMEPORT:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_NEWS_INFO:
                        BattleNetMOTDPacket m = new BattleNetMOTDPacket(GamePacket);
                        String motd = m.GetMOTD();
                        if (motd != String.Empty && MotDMessageReceived != null)
                            MotDMessageReceived(motd);
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_OPTIONALWORK:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_EXTRAWORK:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_REQUIREDWORK:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_TOURNAMENT:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_AUTH_INFO:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_AUTH_CHECK:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_AUTH_ACCOUNTCREATE:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_AUTH_ACCOUNTLOGON:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_AUTH_ACCOUNTLOGONPROOF:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_AUTH_ACCOUNTCHANGE:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_AUTH_ACCOUNTCHANGEPROOF:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_AUTH_ACCOUNTUPGRADE:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_AUTH_ACCOUNTUPGRADEPROOF:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_SETEMAIL:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_RESETPASSWORD:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_CHANGEEMAIL:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_SWITCHPRODUCT:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_WARDEN:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_GAMEPLAYERSEARCH:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_FRIENDSLIST:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_FRIENDSUPDATE:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_FRIENDSADD:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_FRIENDSREMOVE:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_FRIENDSPOSITION:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_CLANFINDCANDIDATES:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_CLANINVITEMULTIPLE:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_CLANCREATIONINVITATION:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_CLANDISBAND:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_CLANMAKECHIEFTAIN:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_CLANINFO:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_CLANQUITNOTIFY:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_CLANINVITATION:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_CLANREMOVEMEMBER:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_CLANINVITATIONRESPONSE:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_CLANRANKCHANGE:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_CLANSETMOTD:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_CLANMOTD:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_CLANMEMBERLIST:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_CLANMEMBERREMOVED:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_CLANMEMBERSTATUSCHANGE:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_CLANMEMBERRANKCHANGE:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.SID_CLANMEMBERINFORMATION:
                        break;
                    default:
                        break;
                };
            }
            else
            {
                switch (b.PacketType)
                {
                    case BattleNetPacket.BattleNetPacketIDConstants.PKT_CLIENTREQ:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.PKT_SERVERPING:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.PKT_KEEPALIVE:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.PKT_CONNTEST:
                        break;
                    case BattleNetPacket.BattleNetPacketIDConstants.PKT_CONNTEST2:
                        break;
                    default:
                        break;
                }
            }

            return true;
        }

        public static bool ProcessPacket(Packet GamePacket)
        {
            BlizzardPacket b = new BlizzardPacket(GamePacket);
            switch (b.PacketProtocol)
            {
                case BlizzardPacket.GamePacketConstants.BNET_PROTOCOL:
                    return ProcessBattleNetPacket(GamePacket);
                    break;
                case BlizzardPacket.GamePacketConstants.W3GS_PROTOCOL:
                    return ProcessW3GSPacket(GamePacket);
                    break;
                default:
                    Console.WriteLine("Discarding Packet");
                    break;
            }
            return false;
        }

        public static bool ProcessW3GSPacket(Packet GamePacket)
        {
            W3GSPacket p = new W3GSPacket(GamePacket);

            //Console.WriteLine("Packet Type: {0}", p.PacketType);

            switch (p.PacketType)
            {
                case W3GSPacket.W3GSPacketIDConstants.W3GS_PING_FROM_HOST:
                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_SLOTINFOJOIN:
                    W3GSSlotInfoPacket slotInfoJoinPacket = new W3GSSlotInfoPacket(GamePacket);

                    List<W3GSSlotInfoPacket.GameSlot> slotInfoJoin = slotInfoJoinPacket.DecodeSlots();                   
                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_REJECTJOIN:
                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_PLAYERINFO:
                    W3GSPlayerInfoPacket playerInfoPacket = new W3GSPlayerInfoPacket(GamePacket);
                    Console.WriteLine("Player Joined: {0}, ID: {1}", playerInfoPacket.GetName(), playerInfoPacket.GetPID());
                    WC3Game.Player player = new WC3Game.Player();
                    player.ID = playerInfoPacket.GetPID();
                    player.Name = playerInfoPacket.GetName();
                    player.IPAddress = playerInfoPacket.IP;
                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_PLAYERLEAVE_OTHERS:
                    W3GSPlayerLeavePacket playerLeavePacket = new W3GSPlayerLeavePacket(GamePacket);
                    int pid = playerLeavePacket.GetPID();
                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_GAMELOADED_OTHERS:
                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_SLOTINFO:
                    W3GSSlotInfoPacket slotInfoPacket = new W3GSSlotInfoPacket(GamePacket);
                    int slotSize = slotInfoPacket.GetSlotInfoSize();
                    List<W3GSSlotInfoPacket.GameSlot> slotInfo = slotInfoPacket.DecodeSlots();
                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_COUNTDOWN_START:
                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_COUNTDOWN_END:
                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_INCOMING_ACTION:
                    W3GSActionPacket actionPacket = new W3GSActionPacket(GamePacket);
                    actionPacket.ProcessActionData();
                    gameActions.AddRange(actionPacket.Actions);

                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_CHAT_FROM_HOST:
                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_START_LAG:
                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_STOP_LAG:
                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_HOST_KICK_PLAYER:
                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_REQJOIN:
                    W3GSReqJoinPacket joinPacket = new W3GSReqJoinPacket(GamePacket);
                    String ipAddresss = joinPacket.IP;
                    Console.WriteLine("REQJOIN: {0}", joinPacket.GetName());
                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_LEAVEGAME:
                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_GAMELOADED_SELF:
                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_OUTGOING_ACTION:
                    W3GSActionPacket outgoingActionPacket = new W3GSActionPacket(GamePacket);
                    outgoingActionPacket.ProcessActionData();
                    gameActions.AddRange(outgoingActionPacket.Actions);
                    String tempString1 = p.Payload.GetString();
                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_OUTGOING_KEEPALIVE:
                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_CHAT_TO_HOST:
                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_DROPREQ:
                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_SEARCHGAME:
                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_GAMEINFO:
                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_CREATEGAME:
                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_REFRESHGAME:
                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_DECREATEGAME:
                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_CHAT_OTHERS:
                    W3GSChatOthersPacket chatOthersPacket = new W3GSChatOthersPacket(GamePacket);
                    String chatothersstring = chatOthersPacket.Payload.GetString();
                    Console.WriteLine("{0}", chatOthersPacket.GetMessage());
                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_PING_FROM_OTHERS:
                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_PONG_TO_OTHERS:
                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_MAPCHECK:
                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_STARTDOWNLOAD:
                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_MAPSIZE:
                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_MAPPART:
                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_MAPPARTOK:
                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_MAPPARTNOTOK:
                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_PONG_TO_HOST:
                    break;
                case W3GSPacket.W3GSPacketIDConstants.W3GS_INCOMING_ACTION2:
                    W3GSActionPacket incomingActionPacket2 = new W3GSActionPacket(GamePacket);
                    incomingActionPacket2.ProcessActionData();
                    gameActions.AddRange(incomingActionPacket2.Actions);
                    break;
                default:
                    break;
            }

            return true;
        }
    }

    public static class Extensions
    {
        public static Int32 ToInt32(this byte dataByte)
        {
            byte[] byteArray = { 0, dataByte };
            int @int32 = 0;
            if (BitConverter.IsLittleEndian)
                byteArray = byteArray.Reverse().ToArray();

            @int32 = BitConverter.ToInt16(byteArray, 0);

            return @int32;
        }

        public static T[] Range<T>(this T[] dataArray, int startIdx, int stopIdx)
        {
            List<T> list = new List<T>();

            if (stopIdx == -1)
                stopIdx = dataArray.Length;

            for (int i = startIdx; i < stopIdx; i++)
            {
                list.Add(dataArray[i]);
            }

            return list.ToArray();
        }

        public static String ExtractString(this byte[] dataArray, int startIdx)
        {
            List<byte> list = new List<byte>();

            int stopIdx = dataArray.Length;

            for (int x = startIdx; x < stopIdx; x++)
            {
                if (dataArray[x] == 0x00)
                {
                    stopIdx = -1;
                    break;
                }

                list.Add(dataArray[x]);
            }

            return list.ToArray().GetString();
        }

        public static T[] Range<T>(this T[] dataArray, int start)
        {
            return dataArray.Range<T>(start, -1);
        }

        public static String GetString(this byte[] byteArray)
        {
            if (byteArray.Length == 0 || byteArray[0] == 0x00)
                return String.Empty;

            return ASCIIEncoding.ASCII.GetString(byteArray);
        }
    }
}
